/blog/
Consuming CLI globs with Clap in Rust
This is just a little thing I ran into while building a CLI client for my custom CMS. What I wanted was a way to run a command on every markdown file in a given directory and have the client add a .content_meta file with the same name and a set of default value. It was pretty easy to handle, but not exactly documented clearly so here’s a blog post about it.
This is using the awesome Clap crate to handle CLI arguments. Clap has everything I needed, I just had to infer how some of it works from different use cases.
...
fn main() {
let matches = App::new("cmscli")
.version("0.1")
.about("Command line interface to the CMS.")
.author("Gatewaynode")
.arg(
Arg::with_name("make_meta")
.short("m")
.long("meta")
.value_name("FILENAME")
.help("Create a metadata file for a piece of content or directory")
.takes_value(true)
.multiple(true),
)
.get_matches();
if matches.is_present("make_meta") {
let filenames = matches.values_of("make_meta").unwrap();
dbg!(&filenames);
for filename in filenames {
//do something with it here
The key here are the argument functions .takes_value(true)
and .multiple(true)
. These change the input collected after the argument -m
from a string to an iterable (probably a vec but that isn’t clear in the debug output).
$ app -m *.md
[src/main.rs:37] &filenames = Values {
iter: Map {
iter: Iter(
[
"Here\’s my page.md",
"Old content goes here to die.md",
],
),
},
}
This let’s me handle command line globs using *
with a for each loop. And later, when it’s time to optimize, we can turn most for each loops into multithreaded operations with the equally awesome Rayon crate.